#region Usings

using System;
using System.Collections.Generic;
using System.Reflection;
using KanbanBoard.Server.Command.DomainModel;
using Microsoft.VisualStudio.TestTools.UnitTesting;

#endregion

namespace KanbanBoard.Tests.Server.Command.DomainModel {
    [TestClass]
    public class PriorityTests {
        private readonly Priority a = Priority.Undefined;
        private readonly Priority b = Priority.Undefined;
        private readonly Priority c = Priority.Undefined;

        [TestMethod]
        public void CanPrioritizeAnItem() {
            a.PutAbove(b);

            AssertPriorities(a, b);
        }

        [TestMethod]
        public void CanDeprioritizeAnItem() {
            a.PutBelow(b);

            AssertPriorities(b, a);
        }

        [TestMethod]
        public void CanSetTheHighestPriority() {
            SetPriorities(a, b);

            c.PutAbove(a);

            AssertPriorities(c, a, b);
        }

        [TestMethod]
        public void CanSetTheLowestPriority() {
            SetPriorities(a, b);

            c.PutBelow(b);

            AssertPriorities(a, b, c);
        }

        [TestMethod]
        public void KeepOtherRelatvePriorities() {
            SetPriorities(a, b, c);

            b.PutAbove(a);

            AssertPriorities(b, a, c);
        }

        [TestMethod]
        public void PrioritizingAnItemAgainstItselfDoesntBreakPriorities() {
            SetPriorities(a, b, c);

            b.PutAbove(b);

            AssertPriorities(a, b, c);
        }

        private static void SetPriorities(params Priority[] priorities) {
            var queue = new Queue<Priority>(priorities);

            while (queue.Count > 1) {
                var priority = queue.Dequeue();
                var nextPriority = queue.Peek();
                nextPriority.PutBelow(priority);
            }
        }

        private static void AssertPriorities(params Priority[] priorities) {
            Func<Priority, int> numeric = priority => (int) typeof (Priority).GetField("numericPriority", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(priority);

            var queue = new Queue<Priority>(priorities);

            while (queue.Count > 1) {
                var priority = queue.Dequeue();
                var nextPriority = queue.Peek();
                Assert.IsTrue(numeric(priority) < numeric(nextPriority));
            }
        }
    }
}